/*
 * Javascript file for game.php module
 * Only contains variables and functions
 * No execution is contained in this file
 * 
 * requires jquery-1.3.2 or later
 * requires chat.js
 */

var gamestate=null;
var updateurl=null;
var refreshurl=null;
var playerlist=null;


//initialize refresh intervals
var gamerefreshId=0;

//ajax response
var response=null; 
var responseurl=null;
var solvedresponse=null;

//unknown function :P
var pzp=null;

//store gamestate as array
var gs=new Array();

//for sudoku cells in sudoku table
var cellwidth=35; //width=height
var cellpadding=10;

var hintcellwidth=30; //width = height
var hintcellpadding=5;

//store row, column and block data
var row=new Array(); //stores id of all cells in a row
var col=new Array(); //stores id of all cells in a column
var block=new Array();//stores id of all cells in a block of 3x3



	function inArray(ary,item){
		for(var i=0;i<ary.length;i++){
			if (ary[i]==item){
				return true;
			}
		}
		return false;
	}
	
	function encode_utf8(s){
		return unescape(encodeURIComponent(s));
	}

	function decode_utf8(s){
		return decodeURIComponent(escape(s));
	}
	
	//convert x,y to index of big block of 3x3 cells (block = 0 to 8)
	function convXYtoBlock(x,y){
		var bx=parseInt(x/3);
		var by=parseInt(y/3);
		return by*3+bx;
	}
	//convert x,y to index of all 81 cells (index = 0 to 80)
	function convXYtoIndex(x,y){
		return y*9+x;
	}


	//define row, col and block arrays
	//e.g. put all cell indexes of a row into row array
	//e.g. row[1] = {9,10,11,12,13,14,15,16,17}
	//e.g. block[0] = { 0, 1, 2
	//				    9,10,11
	//				   18,19,20}
	function populateRowColBlock(){
		var blockId=null;
		for(var i=0;i<9;i++){		
			row[i]=new Array();
			col[i]=new Array();
			block[i]=new Array();
		}
		for(var y=0;y<9;y++){
			for(var x=0;x<9;x++){
				index=convXYtoIndex(x,y);
				blockId=convXYtoBlock(x,y);
				
				row[y].push(index);
				col[x].push(index);
				block[blockId].push(index);
			}
		}
	}


	//'what' can be row,col or block
	//e.g. getOtherItemsIn(row[0],2)
	//     will return {0,1,3,4,5,6,7}
	function getOtherItemsIn(what,id){
		var ary=new Array();
		for(var i=0;i<9;i++){
			if (what[i]!=id){
				ary.push(what[i]);
			}
		}
		return ary;
	}

	//highlight row,col or block
	function highlight(what,id,attr){
		var otheritems=getOtherItemsIn(what[$("#cell-"+id).attr(attr)],id);
		for (var i =0;i<otheritems.length;i++){
			$("#cell-"+otheritems[i]).addClass("rowhighlight");
		}
	}
	
	function removeHighlight(what,id,attr){
		var otheritems=getOtherItemsIn(what[$("#cell-"+id).attr(attr)],id);
		for (var i=0;i<otheritems.length;i++){
			$("#cell-"+otheritems[i]).removeClass("rowhighlight");
		}
	}
	
	
	function putCellHighlights(id){
		highlight(row,id,"row");
		highlight(col,id,"col");
		highlight(block,id,"block");
	}
	function removeCellHighlights(id){
		removeHighlight(row,id,"row");
		removeHighlight(col,id,"col");
		removeHighlight(block,id,"block");
	}

	//set the position of all sudoku cells
	function setPositionSudokuCells(x,y){
		var block=null;
		counter=y*9+x;
		if(y<=8 && x<=8){
			$("#cell-"+counter).css("left",(x*(cellwidth+cellpadding))+"px");
			$("#cell-"+counter).css("top",(y*(cellwidth+cellpadding))+"px");
			block=convXYtoBlock(x,y);
			$("#cell-"+counter).attr("row",y);
			$("#cell-"+counter).attr("col",x);
			$("#cell-"+counter).attr("block",block);
			if(x==8){
				newy=y+1;
				newx=0;
			} else {
				newx=x+1;
				newy=y;
			}
			$("#cell-"+counter).slideDown(5,function(){setPositionSudokuCells(newx,newy);});
			
		}
	}


	//fill in the sudoku cell values according to gamestate
	function updateTable(gamestate){
		gs=gamestate.split('');
		for(var i=0;i<81;i++){
			if(gs[i]!=0){
				$("#cell-"+i).html(gs[i]);
			} else {
				$("#cell-"+i).html("");
			}
		}
	}
	
	//get invalid moves in a cell
	function getUnavailableMoves(id){
		var lst=new Array();
		var cell=$("#cell-"+id);
		var y=cell.attr("row");
		var x=cell.attr("col");
		var b=cell.attr("block");
		var otherIdsInRow=getOtherItemsIn(row[y],id);
		var otherIdsInCol=getOtherItemsIn(col[x],id);
		var otherIdsInBlock=getOtherItemsIn(block[b],id);
		//get moves already filled in the same row
		for(var i=0;i<otherIdsInRow.length;i++){
			if (!inArray(lst,gs[otherIdsInRow[i]])){
				lst.push(gs[otherIdsInRow[i]]);
			}
		}
		//get moves already filled in the same column
		for(var i=0;i<otherIdsInCol.length;i++){
			if (!inArray(lst,gs[otherIdsInCol[i]])){
				lst.push(gs[otherIdsInCol[i]]);
			}
		}
		//get moves already filled in the same block of 3x3
		for(var i=0;i<otherIdsInBlock.length;i++){
			if (!inArray(lst,gs[otherIdsInBlock[i]])){
				lst.push(gs[otherIdsInBlock[i]]);

			}
		}
		//$("#status").append('list='+lst.toLocaleString());
		lst.sort(function(a,b){return (a-b);});//sort in ascending order
		return lst;
	}
	
	//get valid moves in a cell
	function getAvailableMoves(id){
		//to get the move available to make for a particular cell
		var unmoves=getUnavailableMoves(id);
		var amoves=new Array();
		for(var i=1;i<10;i++){
			if(!inArray(unmoves,i)){
				amoves.push(i);
			}
		}

		return amoves;
	}
	
	
	function initializeHintcells(numCells,id){
		var cell=null;
		var counter=1;
		var x=null;
		var y=null;

		var cellspace=hintcellwidth+hintcellpadding;
		
		for(var i=1;i<=numCells;i++){
			cell=$("#hint-"+i);
			
			cell.css("display","block");
			x=(i-1)%3;
			
			y=parseInt((i-1)/3);
			
			cell.css("left",(x*cellspace)+hintcellpadding+"px");
			cell.css("top",(y*cellspace)+hintcellpadding+"px");
			
			entrance=function(v){
				return function(){
					$("#hint-"+v).addClass("hintcellhover");
					};
				};
			leave=function(v){
				return function(){
					$("#hint-"+v).removeClass("hintcellhover");
					};
				};
			click=function(v,id){
				return function(){
					var val=$("#hint-"+v).html();
					$("#cell-"+id).html(val);
					$("#hint-"+v).hide(200,function(){$("#hintmoveswrap").slideUp(100);});
					sendPlayerMove(id,$("#cell-"+id).html());
					};
				};
			
			cell.mouseenter(entrance(i));
			cell.mouseleave(leave(i));
			cell.click(click(i,id));
		}
	}
	

	function setPositionHintwrap(numCells,id){
		var numRows=null;
		var wrap=$("#hintmoveswrap");
		var top=null;
		var left=null;
		var width=null;
		var height=null;
		var cellspace=hintcellwidth+hintcellpadding;
		var cell=$("#cell-"+id);
		switch(numCells){
		case 1:
		case 2:
			width=(numCells*cellspace)+hintcellpadding;
			
			height=cellspace+hintcellpadding;
			wrap.width(width);
			wrap.height(height);
			break;
		default: 
			numRows=parseInt((numCells-1)/3)+1;
			width=(3*cellspace)+hintcellpadding;
			height=(numRows*cellspace)+hintcellpadding;
			wrap.width(width);
			wrap.height(height);
			break;
		}
		
		top=cell.position().top+36;
		left=cell.position().left-((width-cell.width())/2);
		wrap.css("top",top+"px");
		wrap.css("left",left+"px");
	}
	function populateHintcells(id){
		var wrapper=$("#hintmoveswrap");
		var cell=$("#cell-"+id);
		if (pzp!="super"){
			var allowedmoves=[1,2,3,4,5,6,7,8,9];
		} else {
			var allowedmoves=getAvailableMoves(id);
		}
		var cells="";
		for(var i=0;i<allowedmoves.length;i++){
			cells=cells+"<div id=hint-"+(i+1)+" class=hintcell>"+allowedmoves[i]+"</div>";
		}
		setPositionHintwrap(allowedmoves.length,id);
		wrapper.html("");
		wrapper.append(cells);
		
		initializeHintcells(allowedmoves.length,id);

	}
	
	function updatePlayerList(newlist){
		$("#playerlist").html(newlist);
		
		$("div.player").each(
				function(i){
					$(this).attr("contents",$(this).html());
					$(this).mouseenter(
						function(){
							content=$(this).attr("fullname");
							url=$(this).attr("url");
							if(url!=''){
								content="<a href='"+url+"' target=_self>"+content+"</a>";
							}
							$("#playerhighlight").css("left",$(this).position().left+"px");
							$("#playerhighlight").css("top",$(this).position().top+"px");
							$("#playerhighlight").html(content);
							$("#playerhighlight").show();
							
						});
				});

		$("#playerhighlight").mouseleave(
				function(){
					$("#playerhighlight").hide();
				});
	}

	function refreshGame(){
		//get script to update 
		//gamestate, playerlist and players
         $.getScript(refreshurl, 
	        function(){
	        	updateTable(gamestate);
	        	updatePlayerList(playerlist);
	        	processResponse();
	        });  
	}

	function sendPlayerMove(id,val){
		$("#cell-"+id).html(val);
		$.getScript(updateurl+"&cellid="+id+"&cellval="+val,
				function(){
					updateTable(gamestate);
				});
	}
	function processResponse(){
		switch (response){
		case "solved":
			$.getScript(responseurl,
					function(){
						$("#gameadmin").html("").hide();
						$("#solvedMsg").html("").hide();
						$("#solvedMsg").html(solvedresponse).show("slow");
					});
			break;
		case "right":
			break;
		case "wrong":
			//alert("wrong move");
			break;
		case "doesnotexist":
			window.location = responseurl;
			break;
		}

		response=null;
		responseurl=null;
	}

	//initialize events for all sudoku cells;
	function setEventsSudokuCells(){
		for(var i=0;i<=80;i++){
			entrance=function(v){
				return function(){
					if (gs[v]=="0"){
						
						$("#hintmoveswrap").stop(true,true);
						$("#hintmoveswrap").attr("cell",v);
						
						putCellHighlights(v);
						populateHintcells(v);
						$("#hintmoveswrap").slideDown(100);
						
					}
				};
			};
			
			leave=function(v){return function(){
				removeCellHighlights(v);
				$("#hintmoveswrap").slideUp(100);};
		
			};
			
			click=function(v){
				return function(){
					if (gs[v]=="0"){
						$("#hintmoveswrap").hide();
						$("#inputwrap").css("top",$("#cell-"+v).position().top+"px");
						$("#inputwrap").css("left",$("#cell-"+v).position().left+"px");
						$("#input").val("");
						$("#inputwrap").fadeIn(100);
						$("#input").attr("cell",v);
						$("#input").focus();
						putCellHighlights(v);
					}
					
				};
			};
			//we provide fn(i) instead of function() so that values of i will be stored in .click
			$("#cell-"+i).mouseenter(entrance(i));
			$("#cell-"+i).mouseleave(leave(i));
			$("#cell-"+i).click(click(i));
		}
	}

	function setEventsSudokuInputs(){
		//initialize events for hint moves box
		$("#hintmoveswrap").mouseenter(
				function(){
					putCellHighlights($("#hintmoveswrap").attr("cell"));
					$("#hintmoveswrap").stop(true,true);
					$("#hintmoveswrap").show();
				});
		$("#hintmoveswrap").mouseleave(
				function(){
					removeCellHighlights($("#hintmoveswrap").attr("cell"));
					$("#hintmoveswrap").hide();
				});
		
		//initialize events for small inputbox for number entering
		$("#input").keyup(
				function(e){
					switch (e.keyCode){
					case 13://enter
						$("#inputwrap").fadeOut(100);
						var val=$("#input").val();
						var id=$("#input").attr("cell");
						//ajax here
						sendPlayerMove(id,val);
						break;
					case 27://escape key
						$("#input").val("");
						$("#inputwrap").fadeOut(100);
						break;
					default:
						if (e.keyCode<49 || e.keyCode>57){
							$("#input").val("");
						}
					}
				});
		$("#inputwrap").mouseleave(
				function(){
					removeCellHighlights($("#input").attr("cell"));
					$("#inputwrap").fadeOut("fast");
				});
		$("#inputwrap").mousemove(
				function(){
					putCellHighlights($("#hintmoveswrap").attr("cell"));
				});
	}

	function initializeGame(gameSt,updUrl,refreshUrl,playerLst,callback){
		gamestate=gameSt;
		updateurl=updUrl;
		refreshurl=refreshUrl;
		playerlist=playerLst;
		
		//set the row,col,block arrays
		populateRowColBlock();
		
		setEventsSudokuCells(); //all sudoku cells
		
		updateTable(gamestate); //fill the sudoku cell values in
		updatePlayerList(playerlist);
		
		setPositionSudokuCells(0,0); //lay out sudoku cells starting from first cell
		
		setEventsSudokuInputs(); //hint cells, input box
		gamerefreshId=setInterval("refreshGame();", 2000 ); //set the refresh timer
		
		if(callback){
			callback();
		}
	}

